<!--
 * @Date: 2022-12-01 17:59:33
 * @LastEditTime: 2022-12-08 12:47:40
-->
<template>
  <div class="video">
    <!-- 移动端主会场 -->
    <!-- https://y1.videocc.net/static-assets/iflytek/assets/video/ai5.mp4 -->
    <!-- PC主会场 -->
    <!-- https://y1.videocc.net/static-assets/iflytek/assets/video/ai2.mp4 -->
    <!-- 产品 -->
    <!-- https://y1.videocc.net/static-assets/iflytek/assets/video/ai3.mp4 -->
    <video
      src="https://y1.videocc.net/static-assets/iflytek/assets/video/ai3.mp4"
      crossorigin
      ref="videoRef"
      muted
      @click="$refs.videoRef.play"
      width="100"
      height="100"
      poster="https://y1.videocc.net/static-assets/iflytek/assets/video/ai3.mp4?x-oss-process=video/snapshot,t_0,f_png"
    ></video>

    <!-- <img id="cover" ref="converRef" src="https://y1.videocc.net/static-assets/iflytek/assets/video/ai3.mp4?x-oss-process=video/snapshot,t_0,f_jpg,q_100" alt /> -->
    <canvas id="canvas" ref="canvasRef" width="400" height="800"></canvas>
  </div>
</template>

<script>
export default {
  mounted() {},
  data() {
    return {
      videoDom: "",
      coverDom: "",
      canvasDom: "",
      ctx: "",
      width: "",
      height: "",

      startTime: 0,
      endTime: 0,

      sWidth: 1920,
      sHeight: 1080,
      vLeft: 760,
      vTop: 190,
      vWidth: 400,
      vHeight: 800,
      cScale: 1,
      cWidth: 400, // vWidth * cScale
      cHeight: 800, // vHeight * cScale
      cFrames: [],
      cFrameRate: 24,
      cCurFrameIndex: -1,

      // cScale: 0.8,
      // vLeft: 760,
      // vTop: 190,
      // vWidth: 400,
      // vHeight: 0,
      // cWidth: 0,
      // cHeight: 0
    };
  },
  mounted() {
    this.doLoad();
  },
  methods: {
    doLoad() {
      this.videoDom = this.$refs.videoRef;
      // this.coverDom = this.$refs.coverRef;
      this.canvasDom = this.$refs.canvasRef;
      try {
        if (typeof OffscreenCanvas !== "undefined") {
          this.ctx = this.canvasDom
            .transferControlToOffscreen()
            .getContext("2d", {
              imageSmoothingEnabled: true,
              imageSmoothingQuality: "high",
            }); // {imageSmoothingEnabled: true, imageSmoothingQuality:'high', willReadFrequently: true}
        }
      } catch (error) {}
      if (!this.ctx) {
        this.ctx = this.canvasDom.getContext("2d", {
          imageSmoothingEnabled: true,
          imageSmoothingQuality: "high",
        }); // {imageSmoothingEnabled: true, imageSmoothingQuality:'high', willReadFrequently: true}
      }

      this.computeSize(this.sWidth, this.sHeight);

      this.videoDom.addEventListener(
        "loadedmetadata",
        () => {
          if (this.videoDom.videoWidth && this.videoDom.videoHeight)
            this.computeSize(
              this.videoDom.videoWidth,
              this.videoDom.videoHeight
            );
        },
        false
      );

      this.videoDom.addEventListener(
        "play",
        () => {
          this.timerCallback();
        },
        false
      );

      // this.drawCover();
      this.drawCover(
        "https://y1.videocc.net/static-assets/iflytek/assets/video/ai3.mp4?x-oss-process=video/snapshot,t_0,f_jpg,q_100"
      );
    },

    timerCallback() {
      if (
        this.cCurFrameIndex < 0 ||
        (!this.videoDom.paused && !this.videoDom.ended)
      ) {
        this.startTime = Date.now();
        this.drawFrame();
        this.endTime = Date.now();
        console.log("视频帧绘制时长：", this.endTime - this.startTime);

        requestAnimationFrame(this.timerCallback);
        // setTimeout(() => {
        //   this.timerCallback();
        // }, 8);
      }
    },

    computeSize(srcWide, srcHeight) {
      this.sWidth = srcWide;
      this.sHeight = srcHeight;
      this.cWidth = Math.floor(this.vWidth * this.cScale);
      this.cHeight = Math.floor(this.vHeight * this.cScale);
    },

    drawCover() {
      const frameIndex = 0;
      if (this.cCurFrameIndex < frameIndex && !this.cFrames[frameIndex]) {
        const cCover = new Image();
        cCover.crossOrigin = "Anonymous";
        cCover.onload = () => {
          if (cCover.width && cCover.height)
            this.computeSize(cCover.width, cCover.height);
          this.ctx.drawImage(
            cCover,
            this.vLeft,
            this.vTop,
            this.vWidth,
            this.vHeight,
            0,
            0,
            this.cWidth,
            this.cHeight
          );

          let frame = this.ctx.getImageData(0, 0, this.cWidth, this.cHeight);
          if (!this.processFrame(frame)) return false;
          this.cFrames[frameIndex] = frame;
          this.ctx.putImageData(this.cFrames[frameIndex], 0, 0);
          this.cCurFrameIndex = frameIndex;
          return true;
        };
        cCover.src =
          this.videoDom.src + "?x-oss-process=video/snapshot,t_0,f_jpg,q_100";
      }
    },

    drawCover(vSrc) {
      const frameIndex = 0;
      if (this.cCurFrameIndex < frameIndex && !this.cFrames[frameIndex]) {
        fetch(vSrc)
          .then((response) => {
            response.blob().then((blob) => {
              createImageBitmap(blob).then((imageBitmap) => {
                if (imageBitmap && imageBitmap.width && imageBitmap.height) {
                  this.computeSize(imageBitmap.width, imageBitmap.height);
                  this.ctx.drawImage(
                    imageBitmap,
                    this.vLeft,
                    this.vTop,
                    this.vWidth,
                    this.vHeight,
                    0,
                    0,
                    this.cWidth,
                    this.cHeight
                  );
                  let frame = this.ctx.getImageData(
                    0,
                    0,
                    this.cWidth,
                    this.cHeight
                  );
                  if (this.processFrame(frame)) {
                    this.cFrames[frameIndex] = frame;
                    this.ctx.putImageData(this.cFrames[frameIndex], 0, 0);
                    this.cCurFrameIndex = frameIndex;
                  }
                  imageBitmap.close();
                }
              });
            });
          })
          .catch((error) => {});
      }
    },

    drawFrame() {
      const frameIndex = Math.floor(
        this.videoDom.currentTime * this.cFrameRate
      );
      if (frameIndex != this.cCurFrameIndex) {
        if (!this.cFrames[frameIndex]) {
          this.renderFrame(frameIndex)
            .then((frameIndex) => {
              this.ctx.putImageData(this.cFrames[frameIndex], 0, 0);
              this.cCurFrameIndex = frameIndex;
            })
            .catch((error) => {});
        } else {
          this.ctx.putImageData(this.cFrames[frameIndex], 0, 0);
          this.cCurFrameIndex = frameIndex;
        }
      }
    },

    renderFrame(frameIndex) {
      let promise = new Promise((resolve, reject) => {
        this.startTime = Date.now();
        this.ctx.drawImage(
          this.videoDom,
          this.vLeft,
          this.vTop,
          this.vWidth,
          this.vHeight,
          0,
          0,
          this.cWidth,
          this.cHeight
        );
        this.endTime = Date.now();
        console.log(
          frameIndex + "复制视频帧时长:",
          this.endTime - this.startTime
        );

        this.startTime = Date.now();
        let frame = this.ctx.getImageData(0, 0, this.cWidth, this.cHeight);
        if (this.processFrame(frame)) {
          this.cFrames[frameIndex] = frame;
          resolve(frameIndex);
        } else {
          reject(frameIndex);
        }
        this.endTime = Date.now();
        console.log(
          frameIndex + "处理视频帧时长:",
          this.endTime - this.startTime
        );
      });
      return promise;
    },

    processFrame(frame) {
      let pixels = frame.data.length / 4;
      for (let i = 0; i < pixels; i++) {
        let r = frame.data[i * 4 + 0];
        let g = frame.data[i * 4 + 1];
        let b = frame.data[i * 4 + 2];
        let dr = r - 109;
        let dg = g - 161;
        let db = b - 71;

        if (!r && !g && !b) return false;

        if (
          -16 <= dr &&
          dr <= 20 &&
          -16 <= dg &&
          dg <= 16 &&
          -16 <= db &&
          db <= 64
        ) {
          frame.data[i * 4 + 0] = 0;
          frame.data[i * 4 + 1] = 0;
          frame.data[i * 4 + 2] = 0;
          frame.data[i * 4 + 3] = 0;
        } else if (
          -18 <= dr &&
          dr <= 32 &&
          -18 <= dg &&
          dg <= 40 &&
          -32 <= db &&
          db <= 80
        ) {
          frame.data[i * 4 + 0] = 128;
          frame.data[i * 4 + 1] = 128;
          frame.data[i * 4 + 2] = 128;
          frame.data[i * 4 + 3] = 80;
        }
      }
      return true;
    },
  },
};
</script>

<style lang="less" scoped>
.video {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.canvas {
  width: 100;
  height: 200;
}
</style>
